home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 3
/
Gold Medal Software - Volume 3 (Gold Medal) (1994).iso
/
graphics
/
povsuds.arj
/
POVSUDS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-16
|
33KB
|
1,084 lines
/**************
Program: POVSUDS.C (Use medium memory model)
Usage: POVSUDS output.dat
The screen will turn blue and the speaker will beep when the
program has completed its full compliment of spheres.
Basic algorithm from "Computers, Pattern, Chaos, and Beauty" by
Clifford Pickover (St. Martin's Press).
Program by Sam Hobbs, C User's Journal, Sept '91
Purpose:
Draws "osculating" tangent circles of random sizes in two dimensions.
Outputs raytracer data in the form of user definable objects.
Modification History:
-----------------------
11/23/93 Eduard [esp] Schwan
o Updated Dan's updates to support Macintosh models:
o Uncluttered #ifdefs with IBMPC_DISPLAY & MAC_DISPLAY IDs
o No-opped gotoxy for Mac
o Added the write_pov_textures function
o Removed commas from 1.0 object syntax output (write_pov_object)
o Changed #define VERBOSE into command-line option be_verbose variable
11/20/93 Dan Farmer Version 2.0 (IBM version)
o Converted to POV-Ray 2.0.
o Made POV-Ray 2.0 the default ray tracer.
o Put default ray tracer first on menu.
o Dropped POV-Ray 0.5 support.
o Reworked sample camera file.
o Somewhere along the way, I added a color fill to the preview
spheres (for the PC version only).
03/09/93 Eduard [esp] Schwan
o Added code to support Macintosh implementation, more generic
o Added minimal command-line parameter code
o Added missing suds texture IDs, changed sudsNNN to sudsTexNNN for clarity
o Cosmetics on source code, added function separators, made static.
o Allocate humongo circle array dynamically, not as static array.
o Fixed bug that left some spheres out in space, not touching.
o Fixed syntax for POV 0.5, 1.0, 2.0.
o Added user-configurable random distribution functions
01/16/93 dmf Add POV-Ray 1.5 support
01/05/92 Dan Farmer
o Remove MAX_RADIUS_DIVISOR and replace with simple rmax value.
01/02/92 Tim Wegner
o Changed to support new POV-Ray {} syntax
o Added registerVGA call to link with egavga.obj
o Made errors go to stderr
o Added 3D support
o Cleaned up input screen
o Added multiple textures
o Added spherical and rectangular bounding options
o Output to command line parameter
o Home the screen after <A>gain
o Remove POV-Ray Noise and Turbulence variations
11/16/91 Dan Farmer
o Added POV-Ray raytrace output.
o (Uses printf() with redirection to create output include file.)
o Track object extents and auto-center object.
o Get user input for variable parameters.
o Add z to circle_type structure. (Not used yet.)
o Add POV Noise and Turbulence variations
****************/
/*-----------------------------------------------------------------------*/
#if defined (__TURBOC__) || defined (__BORLANDC__)
#define IBMPC_DISPLAY 1
#endif
#if defined(applec) || defined(THINK_C)
#define MAC_DISPLAY 1
#endif
/*==== ANSI C Library headers ====*/
#include <stdlib.h> /* malloc, atof, etc. */
#include <stdio.h>
#include <string.h> /* strcat, etc. */
#include <math.h>
#include <time.h> /* required for random function */
#if defined (IBMPC_DISPLAY)
#include <conio.h>
#include <graphics.h>
#include <dos.h>
#endif
#if defined(MAC_DISPLAY)
// if using Macintosh, include user interface stuff
#include "POVSuds.mac.h"
#else
// This is usually a no-op for non-Mac Systems
#define COOPERATE exit_if_kbhit();
#endif
/*-----------------------------------------------------------------------*/
#define VERSION "2.0a"
#if defined (IBMPC_DISPLAY)
#define CIRCLE(x,y,r) circle(x,y,r)
#define INIT_GRAPHICS() init_graphics()
#define SETBKCOLOR(n) setbkcolor(n)
#define CLOSEGRAPH() closegraph()
#define RECTANGLE(x1,y1,x2,y2) rectangle(x1,y1,x2,y2)
#define CLEARDEVICE() cleardevice()
#define GOTO_XY(x,y) gotoxy(x,y)
#else
// Mac doesn't use these!
#define CIRCLE(x,y,r)
#define INIT_GRAPHICS()
#define SETBKCOLOR(n)
#define CLOSEGRAPH()
#define RECTANGLE(x1,y1,x2,y2)
#define CLEARDEVICE()
#define GOTO_XY(x,y)
#endif
#if !defined(FALSE)
#define FALSE 0
#define TRUE !FALSE
#endif
#if defined (IBMPC_DISPLAY)
#define RANDOMIZE() randomize()
#define RAND() rand()
// RAND_MAX is defined in the ANSI <stdlib.h>, hopefully Borland complies/compiles?
// #define RAND_MAX 32767
#else
#if defined(applec) || defined(THINK_C)
#define SEED() ((int)TickCount())
#endif
/* ANSI Standard random calls */
#define RANDOMIZE() srand(SEED())
#define RAND() rand()
#endif
#define RANDOM() DoDistribution()
#if !defined(DBL)
#define DBL double
#endif
#define MIN_RADIUS 0.01
#define MAX_RADIUS 75.0 /* dmf: Scrap the MAX_RADIUS_DIVISOR */
#define MIN_CIRCLES 1
#define MAX_CIRCLES 5000 /* dmf: Increased max */
#define OLD 1 /* Bounds style */
#define BOX 2
#define SPHERE 3
#define POV20 1
#define POV10 2
#define RAY_MAX POV10
#define DIST_EVEN 1
#define DIST_GAUSS5 2
#define DIST_GAUSS10 3
#define DIST_MAX DIST_GAUSS10
/*-----------------------------------------------------------------------*/
int main(int argc, char *argv[]);
static void generate_circles(void);
static DBL new_radius(DBL x, DBL y, DBL z);
static DBL distance(DBL x, DBL y, DBL z, int i);
static void get_cmdline_args(int argc, char **argv);
#if defined (IBMPC_DISPLAY)
static void get_user_input(void);
static void exit_if_kbhit(void);
static void gerror(int errorcode);
static void init_graphics(void);
static void movetoxy(int x, int y);
int sort_function( const void *a, const void *b);
#endif
static void write_pov_data(void);
static void write_pov_object(DBL x, DBL y, DBL z, DBL r, int t);
static void write_pov_sudsobj(void);
static void write_pov_textures(int num_tex);
static DBL GaussDistribution(int n);
static DBL EvenDistribution(void);
static DBL DoDistribution(void);
#if !defined (min)
static DBL min (DBL value1, DBL value2);
static DBL max (DBL value1, DBL value2);
DBL min(DBL value1, DBL value2)
{
return ( (value1 < value2) ? value1 : value2);
}
DBL max(DBL value1, DBL value2)
{
return ( (value1 > value2) ? value1 : value2);
}
#endif
/*-----------------------------------------------------------------------*/
typedef struct {
DBL x;
DBL y;
DBL z;
DBL r;
} circle_type;
/*-----------------------------------------------------------------------*/
static circle_type *c = NULL;
static int num_circles = 200;
static DBL min_radius = MIN_RADIUS;
static DBL max_radius = MAX_RADIUS;
static short bailout_max = 12000;
static int N;
static int num_textures = 1;
static int raytracer_kind = POV20;
static int distMethod = DIST_EVEN;
static DBL xmax, ymax; /* currently set to screen coordinates in get_user_input() */
static DBL zmax = 0.0;
static DBL rmax;
static int constrain = OLD;
static int be_verbose = FALSE;
static FILE *fpout;
static char *tracers[RAY_MAX] =
{
"POV-Ray v2.0",
"POV-Ray v1.0"
};
static char *disttypes[DIST_MAX] =
{
"Even (Random) Distribution",
"Gaussian Distribution, 5 samples",
"Gaussian Distribution, 10 Samples"
};
static char *begComm[RAY_MAX] = {"//","//"}; // begin/end comments for each tracer syntax
static char *endComm[RAY_MAX] = {"",""};
static char *bounds[] =
{
"centers constrained to rectangular region",
"objects constrained to rectangular region",
"objects constrained to spherical region"
};
#define NUM_BOUNDS (sizeof(bounds)/sizeof(char *))
/*-----------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
#if defined (IBMPC_DISPLAY)
int keypress, done;
#endif
c = (circle_type *)malloc((MAX_CIRCLES+1)*sizeof(circle_type));
#if defined (IBMPC_DISPLAY)
if (argc != 2)
{
printf("\nPOV Suds\n Usage: POVSUDS <outfile>\n");
exit(1);
}
if ((fpout = fopen(argv[1],"w")) == NULL)
{
printf("## Error! Can't open %s ... aborting\n",argv[1]);
exit(1);
}
done = FALSE;
INIT_GRAPHICS();
do {
SETBKCOLOR(0); /* color to black */
CLEARDEVICE();
get_user_input();
CLEARDEVICE();
generate_circles();
// Redisplay in z sorted order, colored by r
qsort( (void *)c, num_circles,sizeof(c[3]), sort_function);
for (N = 0; N < num_circles; N++) {
setfillstyle(SOLID_FILL, (int) c[N].r % getmaxcolor() +1);
//pieslice(c[N].x, c[N].y, 0,360, c[N].r);
fillellipse(c[N].x, c[N].y, c[N].r, c[N].r);
}
/* Frame the screen to show user that program is finished */
GOTO_XY(1,3);
fputs("\007", stdout); /* beep */
fputs("<W>rite <Q>uit <R>edo",stdout);
RECTANGLE(0, 0, getmaxx(), getmaxy()); /* draw frame */
keypress = getch(); /* wait for keypress */
switch (keypress)
{
case 'R':
case 'r':
done = FALSE;
break;
case 'W':
case 'w':
write_pov_data(); /* write PoV data */
CLOSEGRAPH();
return(0); /* quit */
case 'Q':
case 'q':
done = TRUE;
break;
default:
break;
}
} while (!done);
CLOSEGRAPH();
#else
// The Mac way...
get_cmdline_args(argc, argv);
generate_circles();
write_pov_data(); /* write PoV data */
if ((fpout) && (fpout != stdout))
fclose(fpout);
#endif
if (c != NULL)
free(c);
return 0;
} // main
/*-----------------------------------------------------------------------*/
static void generate_circles()
{
DBL x_pos, y_pos, z_pos, radius;
short bailout;
RANDOMIZE();
/* Note that xmax and ymax would probably be better for raytrace
output if defined as a radius instead of screen rez. This would
clump the circles into a larger circular area. */
/* constrain to this sphere - tucked safely at the end of c[] */
c[MAX_CIRCLES].x = xmax/2;
c[MAX_CIRCLES].y = ymax/2;
c[MAX_CIRCLES].z = zmax/2;
c[MAX_CIRCLES].r = min(xmax,ymax) * 0.5;
/* draw the rest of the circles */
for (N = 0; N < num_circles ; N++)
{
bailout = 0;
do {
x_pos = RANDOM() * xmax;
y_pos = RANDOM() * ymax;
if(zmax > 0.0)
z_pos = RANDOM() * zmax;
else
z_pos = 0.0;
radius = new_radius(x_pos, y_pos, z_pos);
if (bailout_max > 0)
bailout++;
if ((bailout & 31) == 31) // breathe every 32 times through
COOPERATE
} while ( ((radius < min_radius) || (radius > max_radius)) && (bailout < bailout_max) );
if (bailout >= bailout_max)
{
printf("\nERROR! couldn't place circle #%d after %d tries... giving up.\n", N, bailout);
num_circles = N; /* Set a new lower # circles! */
break; /* out of for loop */
}
else
{
CIRCLE(x_pos,y_pos, radius);
c[N].x = x_pos;
c[N].y = y_pos;
c[N].z = z_pos;
c[N].r = radius;
GOTO_XY(1,1);
if(be_verbose)
printf("%4d Units: sphere { <%7.3g, %7.3g, %7.3g>, %7.3g } \r",N,x_pos,y_pos,z_pos,radius);
else
printf("%4d Units\r",N);
}
}
} // generate_circles
/*-----------------------------------------------------------------------*/
/* Function: new_radius(x,y,z)
Purpose:
Returns the distance from the point x,y,z to the nearest circle.
Aborts and returns the calculated negative or zero distance if x,y
lies on or inside of another circle
*/
static DBL new_radius(DBL x, DBL y, DBL z)
{
int i, touched;
DBL radius, dist_circle;
radius = max_radius;
switch (constrain)
{
case OLD:
break;
case BOX:
/* don't let get outside box */
if (radius > x)
radius = x;
if (radius > xmax - x)
radius = xmax - x;
if (radius > y)
radius = y;
if (radius > ymax - y)
radius = ymax - y;
if (zmax > min_radius*2)
{
if (radius > z)
radius = z;
if (radius > zmax-z)
radius = zmax-z;
}
break;
case SPHERE:
dist_circle = distance(x,y,z,MAX_CIRCLES); /* dist pt to center */
if (dist_circle >= 0)
return 0.0; /* center ouside bounding sphere */
else
radius = min(radius, -dist_circle);
break;
}
if (N == 0)
touched = TRUE; // first one's always OK
else
for (i=0, touched=FALSE; i < N; i++)
{
dist_circle = distance(x, y, z, i);
#if defined (IBMPC_DISPLAY)
if(be_verbose) {
GOTO_XY (1,2);
printf("Test #%d\r",i);
}
GOTO_XY(1,3); printf(" \r"); // erase "Touched" message
#endif
// find smallest radius so far
if (dist_circle <= radius)
{
radius = dist_circle;
touched = TRUE; // yes, we bumped into another circle
#if defined (IBMPC_DISPLAY)
if(be_verbose) {
GOTO_XY(1,3);
printf("Touched\r");
}
#endif
}
// if we're too small, return
if (radius < min_radius)
return radius;
}
if (touched)
return radius;
else
return 0.0; // if we didn't touch another circle, return as invalid
} // new_radius
/*-----------------------------------------------------------------------*/
/* Function: distance(x,y,z,i)
Purpose:
Returns the distance from the point x,y,z to edge of circle i.
Returns a negative value or zero distance if x,y is inside or on
circle i.
*/
static DBL distance(DBL x, DBL y, DBL z, int i)
{
DBL xdist, ydist, zdist, distancesq, dist;
xdist = x - c[i].x;
ydist = y - c[i].y;
zdist = z - c[i].z;
distancesq = (xdist*xdist) + (ydist*ydist) + (zdist*zdist);
dist = sqrt(distancesq) - c[i].r;
return (dist);
} // distance
/*-----------------------------------------------------------------------*/
static void get_cmdline_args(int argc, char **argv)
{
int c;
char filename[64];
c = 1;
fpout = stdout;
while (c < argc)
{
if ((argv[c][0] == '-') || (argv[c][0] == '/'))
{
switch (argv[c][1])
{
case 'o': // -oOutputFileName
case 'O':
// get filename
strcpy(filename,&argv[c][2]);
// if no suffix, add one
if (!strchr(filename,'.'))
strcat(filename,".inc");
if((fpout=fopen(filename,"w")) == NULL)
{
printf("Can't open %s ... aborting\n",filename);
exit(1);
}
break;
case 'n': // -nNumSpheres
case 'N':
num_circles = atoi(&argv[c][2]);
if ((num_circles <= MIN_CIRCLES) || (num_circles > MAX_CIRCLES))
num_circles = MIN_CIRCLES;
break;
case 'x': // -xXregionOfSpheres
case 'X':
xmax = atoi(&argv[c][2]);
if ((xmax < 0.0) || (xmax > 999.0))
xmax = 100.0;
break;
case 'y': // -yYregionOfSpheres
case 'Y':
ymax = atoi(&argv[c][2]);
if ((ymax < 0.0) || (ymax > 999.0))
ymax = 100.0;
break;
case 'z': // -zZregionOfSpheres
case 'Z':
zmax = atoi(&argv[c][2]);
if ((zmax < 0.0) || (zmax > 999.0))
zmax = 0.0;
break;
case 'r': // -rRayTracerType (1=PoV 2.0, 2=PoV 1.0)
case 'R':
raytracer_kind = atoi(&argv[c][2]);
if ((raytracer_kind < 1) || (raytracer_kind > RAY_MAX))
raytracer_kind = POV20;
break;
case 'a': // -aMinRadius
case 'A':
min_radius = atof(&argv[c][2]);
if ((min_radius <= MIN_RADIUS) || (min_radius > 10.0))
min_radius = MIN_RADIUS;
break;
case 'b': // -bMaxRadius
case 'B':
max_radius = atof(&argv[c][2]);
if ((max_radius <= 1.0) || (max_radius > MAX_RADIUS))
max_radius = MAX_RADIUS;
break;
case 'd': // -dDistMethod (1=even, 2=Gauss5, 3=Gauss10)
case 'D':
distMethod = atoi(&argv[c][2]);
if ((distMethod < 1) || (distMethod > DIST_MAX))
distMethod = DIST_EVEN;
break;
case 'k': // -kBoundingKind
case 'K':
constrain = atoi(&argv[c][2]);
if ((constrain < 1) || (constrain > NUM_BOUNDS))
constrain = 1;
break;
case 't': // -tNumTextures
case 'T':
num_textures = atoi(&argv[c][2]);
if ((num_textures < 1) || (num_textures > 100))
num_textures = 1;
break;
case 'v': // -v (Be Verbose)
case 'V':
be_verbose = TRUE;
break;
default:
printf("Error! Unrecognized parameter '%s', ignored.\n",argv[c]);
break;
} // switch
}
else
printf("Error! Unrecognized parameter '%s', ignored.\n",argv[c]);
/* go to next parameter */
c++; /* NOT! :-) [esp] */
}
} // get_cmdline_args
#if defined (IBMPC_DISPLAY)
/*-----------------------------------------------------------------------*/
/*
Get parameters from user.
*/
static void get_user_input()
{
/* Get user input */
/* Note that the ranges here are pretty much arbitrary values at this
time. Need to test to establish good defaults and ranges. dmf */
int i;
char buf[200];
/* center center boundaries to screen coordinates */
xmax = getmaxx();
ymax = getmaxy();
movetoxy(0, 0);
printf("\nPOV SUDS - Generate Osculating Objects\n\n");
printf("Press <Return> to keep same values\n");
printf("Current values shown in []\n");
printf("\nEnter Ray Tracer\n");
for (i=0; i<RAY_MAX; i++)
printf("%-d=%s\n", i+1, tracers[i]);
printf("Choice [%-d] : ", raytracer_kind);
gets(buf);
sscanf(buf,"%d->", &raytracer_kind);
if(raytracer_kind==0) exit(0);
if ((raytracer_kind < 1) || (raytracer_kind > RAY_MAX))
raytracer_kind=POV20;
printf("\nEnter Type of Bounds\n");
for (i=0; i<NUM_BOUNDS; i++)
printf("%-d=%s\n", i+1, bounds[i]);
printf("Choice [%-d] : ",constrain);
gets(buf);
sscanf(buf,"%d->",&constrain);
if ((constrain < 1) || (constrain > NUM_BOUNDS))
constrain = OLD;
printf("\nRegion Containing Spheres:\n");
printf(" X from 0 to %-3g (fixed to screen resolution)\n",xmax);
printf(" Y from 0 to %-3g (fixed to screen resolution)\n",ymax);
printf(" Z from 0 to zmax (user set)\n");
printf("Enter zmax (depth of region ) [%-g] : ",zmax);
gets(buf);
sscanf(buf,"%lf->",&zmax);
if (zmax < 0)
zmax = 0;
CLEARDEVICE();
movetoxy(0,0);
printf("\nPOV SUDS - Generate Osculating Objects\n\n");
printf("Press <Return> to keep same values\n");
printf("Current values shown in []\n");
printf("\nEnter Number Textures [%-d] : ",num_textures);
gets(buf);
sscanf(buf,"%d->",&num_textures);
if (num_textures < 1)
num_textures = 1;
printf("\nEnter Max Spheres (%d-%d) [%-d] : ",
MIN_CIRCLES, MAX_CIRCLES,num_circles);
gets(buf);
sscanf(buf,"%d",&num_circles);
if (num_circles < MIN_CIRCLES)
num_circles = MIN_CIRCLES;
if (num_circles > MAX_CIRCLES)
num_circles = MAX_CIRCLES;
printf("\nEnter Min Radius (0.01-10) [%-7.4lf] : ",min_radius);
gets(buf);
sscanf(buf,"%lf",&min_radius);
if (min_radius < MIN_RADIUS)
min_radius = MIN_RADIUS;
if (min_radius > 10.0)
min_radius = 10.0;
printf("\nEnter Max Radius (1-100) [%-4lf] : ",max_radius);
gets(buf);
sscanf(buf,"%lf",&max_radius);
if (max_radius < min_radius)
max_radius = min_radius;
if (max_radius > MAX_RADIUS)
max_radius = MAX_RADIUS;
printf("\nEnter Distribution Type\n");
for (i=0; i<DIST_MAX; i++)
printf("%-d=%s\n", i+1, disttypes[i]);
printf("Choice [%-d] : ", distMethod);
gets(buf);
sscanf(buf,"%d->", &distMethod);
if ((distMethod < 1) || (distMethod > DIST_MAX))
distMethod = DIST_EVEN;
} // get_user_input
/*-----------------------------------------------------------------------*/
static void exit_if_kbhit()
{
if (kbhit())
{
getch();
closegraph();
exit(1);
}
} // exit_if_kbhit
/*-----------------------------------------------------------------------*/
static void gerror(int errorcode)
{
fprintf(stderr,"Graphics error: %s\n", grapherrormsg(errorcode));
fprintf(stderr,"Press any key to halt.");
getch();
exit(1);
} // gerror
/*-----------------------------------------------------------------------*/
/* Uses the Borland BGI drivers */
static void init_graphics (void)
{
int gdriver = DETECT, gmode, errorcode;
/* cut following 3 lines if you want to dynamically load egavga.bgi */
errorcode = registerbgidriver(EGAVGA_driver);
if (errorcode < 0)
gerror(errorcode);
initgraph(&gdriver, &gmode, "");
errorcode = graphresult();
if (errorcode != grOk)
gerror(errorcode);
} // init_graphics
/*-----------------------------------------------------------------------*/
#define VIDEO 0x10
static void movetoxy(int x, int y)
{
union REGS regs;
regs.h.ah = 2;
regs.h.dh = y;
regs.h.dl = x;
regs.h.bh = 0;
int86(VIDEO,®s,®s);
} // movetoxy
/*-----------------------------------------------------------------------*/
//Sort function for qsort
int sort_function( const void *a, const void *b)
{
if(a < b) return -1;
if(a > b) return 1;
return 0;
} // sort_function
#endif // IBMPC_DISPLAY
/*-----------------------------------------------------------------------*/
// Write an #include file for POV-Ray of a union of declared objects.
// The composite is on the X/Y plane, left-handed coordinate system.
// Uses a main datafile that defines "SudsObject" and associated textures
// sudsTex1, sudsTex2...
// Format:
//
// (POV 1.0)
// #declare Suds = composite {
// object { SudsObject scale <x y z> translate <x y z> texture { sudsTex1 } }
// object { SudsObject scale <x y z> translate <x y z> texture { sudsTex2 } }
// }
//
// (POV 2.0)
// #declare Suds = union {
// object { SudsObject scale <x, y, z> translate <x, y, z> texture { sudsTex1 } }
// object { SudsObject scale <x, y, z> translate <x, y, z> texture { sudsTex2 } }
// }
//
static void write_pov_data(void)
{
int i,t;
DBL x_pos, y_pos, z_pos, radius;
DBL x_len, y_len, z_len;
DBL half_x, half_y, half_z;
DBL x_center, y_center, z_center;
DBL maxr_extent = 0.0;
DBL maxx_extent = 0.0;
DBL maxy_extent = 0.0;
DBL maxz_extent = 0.0;
DBL minr_extent = 1.7e+10;
DBL minx_extent = 1.7e+10;
DBL miny_extent = 1.7e+10;
DBL minz_extent = 1.7e+10;
/* Write header to file */
fprintf(fpout,"%s File generated with POV-Suds Utility (version %s) %s\n",
begComm[raytracer_kind-1], VERSION, endComm[raytracer_kind-1]);
/* Write texture list to file */
write_pov_textures(num_textures);
/* Write SudsObject template to file */
write_pov_sudsobj();
/* Write the suds to file */
switch(raytracer_kind)
{
case POV10:
fprintf(fpout,"\n#declare Suds = composite {\n");
break;
case POV20:
fprintf(fpout,"\n#declare Suds = union {\n");
break;
}
/* Write out each of the objects */
for (i=0; i<num_circles; i++)
{
x_pos = c[i].x;
y_pos = c[i].y;
z_pos = c[i].z;
radius = c[i].r;
t = i % num_textures; // roll through the textures...
write_pov_object(x_pos, y_pos, z_pos, radius, t);
/* keep track of the overall extents */
maxx_extent = max(x_pos+radius, maxx_extent);
maxy_extent = max(y_pos+radius, maxy_extent);
maxz_extent = max(z_pos+radius, maxz_extent);
maxr_extent = max(radius, maxr_extent);
minx_extent = min(x_pos-radius, minx_extent);
miny_extent = min(y_pos-radius, miny_extent);
minz_extent = min(z_pos-radius, minz_extent);
minr_extent = min(radius, minr_extent);
}
/* Center the composite object, based on extents */
x_len = maxx_extent - minx_extent;
y_len = maxy_extent - miny_extent;
z_len = maxz_extent - minz_extent;
half_x = x_len * 0.5;
half_y = y_len * 0.5;
half_z = z_len * 0.5;
x_center = minx_extent + half_x;
y_center = miny_extent + half_y;
z_center = minz_extent + half_z;
switch (raytracer_kind)
{
case POV10:
fprintf(fpout," translate <%g %g %g> %s Center it\n",
-x_center, -y_center, -z_center, begComm[raytracer_kind-1]);
fprintf(fpout,"} %s Suds composite\n", begComm[raytracer_kind-1]);
fprintf(fpout,"\n");
fprintf(fpout,"#declare Suds_Bounding_Box = box { <-1 -1 -1> <1 1 1>\n");
fprintf(fpout," scale <%g %g %g>\n", x_len, y_len, z_len);
fprintf(fpout,"} %s Suds_Bounding_Box\n", begComm[raytracer_kind-1]);
fprintf(fpout,"\n");
break;
case POV20:
fprintf(fpout," translate <%g, %g, %g> %s Center it\n",
-x_center, -y_center, -z_center, begComm[raytracer_kind-1]);
fprintf(fpout,"%s NOTE: In POV-Ray 2.0, auto-bounded!\n", begComm[raytracer_kind-1]);
fprintf(fpout,"} %s Suds union\n", begComm[raytracer_kind-1]);
fprintf(fpout,"\n");
break;
}
fprintf(fpout,"%s Object Extents: %s\n",
begComm[raytracer_kind-1], endComm[raytracer_kind-1]);
fprintf(fpout,"%s Min X = %7.2g, Y = %7.2g, Z = %7.2g, R = %7.2g %s\n",
begComm[raytracer_kind-1], minx_extent, miny_extent, minz_extent, minr_extent, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Max X = %7.2g, Y = %7.2g, Z = %7.2g, R = %7.2g %s\n",
begComm[raytracer_kind-1], maxx_extent, maxy_extent, maxz_extent, maxr_extent, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Objects generated : %5d %s\n",
begComm[raytracer_kind-1], N, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Textures Needed : %5d %s\n",
begComm[raytracer_kind-1], num_textures, endComm[raytracer_kind-1]);
fprintf(fpout,"\n\n%s ------------------------------- %s\n",
begComm[raytracer_kind-1], endComm[raytracer_kind-1]);
fprintf(fpout,"%s POV SUDS settings used to generate this file %s\n\n",
begComm[raytracer_kind-1], endComm[raytracer_kind-1]);
fprintf(fpout,"%s Ray Tracer = %d (%s) %s\n",
begComm[raytracer_kind-1], raytracer_kind,tracers[raytracer_kind-1], endComm[raytracer_kind-1]);
fprintf(fpout,"%s Type of Bounds = %d (%s) %s\n",
begComm[raytracer_kind-1], constrain,bounds[constrain-1], endComm[raytracer_kind-1]);
fprintf(fpout,"%s Region Containing Objects:%s\n",
begComm[raytracer_kind-1], endComm[raytracer_kind-1]);
fprintf(fpout,"%s X from 0 to %7.2f (fixed to screen resolution) %s\n",
begComm[raytracer_kind-1], xmax, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Y from 0 to %7.2f (fixed to screen resolution) %s\n",
begComm[raytracer_kind-1], ymax, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Z from 0 to %7.2f (user setting of zmax) %s\n",
begComm[raytracer_kind-1], zmax, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Number of Textures = %8d %s\n",
begComm[raytracer_kind-1], num_textures, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Max Spheres = %8d %s\n",
begComm[raytracer_kind-1], num_circles, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Min Radius = %8.4g %s\n",
begComm[raytracer_kind-1], min_radius, endComm[raytracer_kind-1]);
fprintf(fpout,"%s Max Radius = %8.4g %s\n",
begComm[raytracer_kind-1], max_radius, endComm[raytracer_kind-1]);
} // write_pov_data
/*-----------------------------------------------------------------------*/
/* Write a single circle out to PoV Ray format as a user-definable object */
static void write_pov_object(DBL x, DBL y, DBL z, DBL r, int t)
{
DBL x_scale = r;
DBL y_scale = x_scale;
DBL z_scale = x_scale;
DBL x_center = x;
DBL y_center = y;
DBL z_center = z;
switch (raytracer_kind)
{
case POV10:
fprintf(fpout,
" object { SudsObject scale <%8.4g %8.4g %8.4g> translate <%8.4g %8.4g %8.4g> texture {sudsTex%-2d} }\n",
x_scale, y_scale, z_scale, x_center, y_center, z_center, t+1);
break;
case POV20:
fprintf(fpout,
" object { SudsObject scale <%g, %g, %g> translate <%g, %g, %g> texture {sudsTex%-2d} }\n",
x_scale, y_scale, z_scale, x_center, y_center, z_center, t+1);
break;
}
} // write_pov_object
/*-----------------------------------------------------------------------*/
/* Write an example SudsObject in PoV Ray format */
static void write_pov_sudsobj(void)
{
fprintf(fpout, "\n/* --- Example Suds Object Declaration --- */\n\n");
switch (raytracer_kind)
{
case POV10:
fprintf(fpout, "#declare SudsObject = object { sphere { <0 0 0> 1.0 } }\n");
break;
case POV20:
fprintf(fpout, "#declare SudsObject = sphere { <0, 0, 0> 1.0 }\n");
break;
}
fprintf(fpout, "\n/* --- end of Suds Object Declaration */\n");
} // write_pov_sudsobj
/*-----------------------------------------------------------------------*/
/* Write a list of texture declarations in PoV Ray format */
static void write_pov_textures(int num_tex)
{
int t;
fprintf(fpout, "\n/* --- Example texture declarations, alter them to your liking --- */\n");
for (t=1; t<=num_tex; t++)
{
fprintf(fpout, "\n");
switch (raytracer_kind)
{
case POV10:
fprintf(fpout, "#declare sudsTex%-2d = texture {\n", t);
fprintf(fpout, " color red %g green %g blue %g\n", EvenDistribution(), EvenDistribution(), EvenDistribution());
fprintf(fpout, " ambient 0.2 diffuse 0.7\n");
fprintf(fpout, " specular 0.8 roughness 0.01\n");
fprintf(fpout, "} // sudsTex%-2d\n", t);
break;
case POV20:
fprintf(fpout, "#declare sudsTex%-2d = texture {\n", t);
fprintf(fpout, " pigment {\n");
fprintf(fpout, " color rgb <%g,%g,%g>\n", EvenDistribution(), EvenDistribution(), EvenDistribution());
fprintf(fpout, " }\n");
fprintf(fpout, " // normal { wrinkles, bumps, etc. }\n");
fprintf(fpout, " finish {\n");
fprintf(fpout, " ambient 0.2 diffuse 0.7\n");
fprintf(fpout, " specular 0.8 roughness 0.01\n");
fprintf(fpout, " }\n");
fprintf(fpout, "} // sudsTex%-2d\n", t);
break;
}
}
fprintf(fpout, "\n/* --- end of texture declarations */\n");
} // write_pov_textures
/*-----------------------------------------------------------------------*/
static DBL GaussDistribution(int n)
{
register int i;
register DBL r = 0.0;
// take n samples
for (i=1; i <= n; i++) {
r += (DBL)RAND();
}
// divide by n to get average
r /= (DBL)n;
// divide by max rand. # to get value between 0.0 and 1.0
r /= (DBL)RAND_MAX;
return (r);
} // GaussDistribution
/*-----------------------------------------------------------------------*/
static DBL EvenDistribution(void)
{
register DBL r = 0.0;
// divide by max rand. # to get value between 0.0 and 1.0
r = (DBL)RAND() / (DBL)RAND_MAX;
return (r);
} // EvenDistribution
/*-----------------------------------------------------------------------*/
// Returns a number between 0 and 1.
static DBL DoDistribution(void)
{
register DBL r = 0.0;
switch (distMethod)
{
case DIST_EVEN:
r = EvenDistribution();
break;
case DIST_GAUSS5:
r = GaussDistribution(5);
break;
case DIST_GAUSS10:
r = GaussDistribution(10);
break;
}
return r;
} // DoDistribution